package connectionpool;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.util.Date;

/**
 * @author Cipri_L
 * 
 */
public class ConnectionHandler implements Runnable, IConnectionHandler {
	private Socket socket;
	private String WEB_ROOT;
	private ServerState server_state;

	public ConnectionHandler(Socket socket, String WEB_ROOT,
			ServerState server_state) {
		this.socket = socket;
		this.WEB_ROOT = WEB_ROOT;
		this.server_state = server_state;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see web_server.IConnectionHandler#run()
	 */
	@Override
	public void run() {
		try {
			handleConnection(socket);
		} catch (IOException ioe) {
			System.err.println("IOException: " + ioe);
			//ioe.printStackTrace();
		}
		// System.out.println("endConnectionHandler!");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see web_server.IConnectionHandler#handleConnection(java.net.Socket)
	 */
	@Override
	public void handleConnection(Socket socket) throws IOException {

		/**
		 * Read the http request from the client from the socket interface into
		 * a buffer.
		 */
		BufferedReader input = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));

		/**
		 * Prepare a outputstream from us to the client, this will be used
		 * sending back our response (header + requested file) to the client.
		 */
		DataOutputStream output = new DataOutputStream(socket.getOutputStream());

		http_handler(input, output);

		socket.close();
	}

	/**
	 * @param input
	 * @param output
	 *            - handle http_request: parse request and deliver response -
	 *            handles only GET - this implementation of the hypertext
	 *            transfer protocol is very basic and stripped down
	 */
	private void http_handler(BufferedReader input, DataOutputStream output) {
		
		/**
		 * method adapted from
		 * http://fragments.turtlemeat.com/javawebserver.php
		 */
		
		int method = 0; // 1 get, 2 head, 0 not supported
		// String http = new String(); //a bunch of strings to hold
		String path = ""; // the various things, what http v, what path,
		// String file = new String(); //what file
		// String user_agent = new String(); //what user_agent
		// String last_running_req ;
		try {
			// This is the two types of request we can handle
			// GET /index.html HTTP/1.0
			// HEAD /index.html HTTP/1.0
			String tmp = input.readLine(); // read from the stream
			if (tmp == null)
				tmp = "";

			String tmp2 = tmp.toString();
			tmp = tmp.toUpperCase(); // convert it to uppercase
			if (tmp.startsWith("GET")) { // compare it is it GET
				method = 1;
			} // if we set it to method 1
			if (tmp.startsWith("HEAD")) { // same here is it HEAD
				method = 2;
			} // set method to 2

			if (method == 0) { // not supported
				try {
					output.writeBytes(construct_http_header(501, 0));
					output.close();
					return; // http_handler return
				} catch (Exception e3) { // if some error happened catch it
					// e3.printStackTrace();
					// System.err.println("error:" + e3);
				} // and display error
			}

			path = extractPath(tmp2);
			// System.out.println("**** " + path);
			if (server_state == ServerState.MAINTENANCE) {
				// path = extractPath(tmp2);
				path = "index.html";
				// output.writeBytes("Running");
			}
			// else{
			// /**
			// * server responds with index.html from maintenance_directory
			// */
			// //output.writeBytes("Maintenace");
			// path = "index.html";
			// }

		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("error:" + e);
		} // catch any exception

		/**
		 * path - we now have the path to the file the browser wants to open
		 */
		String newPath = path.replace('/', File.separatorChar);
		path = newPath;
		// last_running_req = new String(path);
		path = WEB_ROOT + File.separator + path;

		try {
			// needed for special characters in html
			path = java.net.URLDecoder.decode(path, "UTF-8");

		} catch (UnsupportedEncodingException e3) {
			// TODO Auto-generated catch block
			e3.printStackTrace();
		}

		//System.out.println("Client requested: "+  path);

		/**
		 * We test to see if we have a directory requested. If it is directory,
		 * we diplay the files in the directory and return from http_handler.
		 */

		File file2 = new File(path);

		if (file2.exists()) {
			if (file2.isDirectory()) {
				// System.out.println("directory:");
				/**
				 * server tries to respond with index.html from the directory
				 * specified in path. if index.html does not exist it prints the
				 * file-listing of that directory
				 */

				/**
				 * we can add default.html or index.htm
				 */

				File index_html = new File(path + File.separator + "index.html");
				if (index_html.exists()) {
					String indexName = "index.html";
					if (path.endsWith(File.separator)) {
						path += indexName;
					} else {
						path += File.separator + indexName;
					}

					// System.out.println("found index: " + path);
				} else {

					int start = WEB_ROOT.length();

					String name = path.substring(start);
					name = name.replace(File.separatorChar, '/');
					// String name = path ;
					// System.out.println("name: " + name);
					// write out the header, 200 ->everything is ok we are all
					// happy.
					if (name.endsWith("/")) {
						name = name.substring(0, name.lastIndexOf("/"));
						// System.out.println("name2: " + name);
					}

					try {
						output.writeBytes(construct_http_header(200, 0));

						this.listDirectory(file2, name);

						// close the stream
						output.close();
						return; // return from http_handler
					} catch (IOException e) {
						// TODO Auto-generated catch block
						// e.printStackTrace();
					}
				}
			}
		} 
//		else {
//			System.out.println("file not exist: " + path);
//		}

		FileInputStream requestedfile = null;
		try {
			// try to open the file,
			requestedfile = new FileInputStream(path);
		} catch (Exception e) {
			try {
				// if you could not open the file send a 404

				output.writeBytes(construct_http_header(404, 0));
				String notFound = "\t\t!!!File not Found!!!";
				output.writeBytes(notFound);
				// close the stream
				output.close();

			} catch (Exception e2) {
			}
			// e.printStackTrace();
			// System.out.println(e);
			// System.err.println("error:" + e);

			// return from http_handler
			return;
		}

		// happy day scenario
		try {
			int type_is = 0;
			// find out what the filename ends with,
			// so you can construct a the right content type
			if (path.endsWith(".zip")) {
				type_is = 3;
			}
			if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
				type_is = 1;
			}
			if (path.endsWith(".gif")) {
				type_is = 2;
			}
			if (path.endsWith(".ico")) {
				type_is = 4;
			}
			if (path.endsWith(".css")) {
				type_is = 5;
			}
			if (path.endsWith(".txt")) {
				type_is = 6;
			}
			if (path.endsWith(".png")) {
				type_is = 7;
			}

			// write out the header, 200 ->everything is ok we are all happy.
			output.writeBytes(construct_http_header(200, type_is));

			// if it was a HEAD request, we don't print any BODY
			if (method == 1) { // 1 is GET 2 is head and skips the body
				byte[] buffer = new byte[1024];
				while (!Thread.currentThread().isInterrupted()) {
					// System.out.println("connectionHandler: "+Thread.currentThread().isInterrupted());
					// read the file from filestream, and print out through the
					// client-outputstream on a byte per byte base.
					int b = requestedfile.read(buffer, 0, 1024);
					if (b == -1) {
						break; // end of file
					}
					output.write(buffer, 0, b);
				}
				// clean up the files, close open handles

			}
			output.close();
			requestedfile.close();
		} catch (Exception e) {
			Thread.currentThread().interrupt(); // preserve the interruption
		}

	}// http_handler

	private String extractPath(String tmp2) {
		// TODO Auto-generated method stub
		/**
		 * tmp contains "GET /index.html HTTP/1.0 ......." find first space find
		 * next space copy what's between minus slash, then you get "index.html"
		 */

		int start = 0;
		int end = 0;
		for (int a = 0; a < tmp2.length(); a++) {
			if (tmp2.charAt(a) == ' ' && start != 0) {
				end = a;
				break;
			}
			if (tmp2.charAt(a) == ' ' && start == 0) {
				start = a;
			}
		}

		return tmp2.substring(start + 2, end); // fill in the path
	}

	// this method makes the HTTP header for the response
	// the headers job is to tell the browser the result of the request
	// among if it was successful or not.
	private String construct_http_header(int return_code, int file_type) {
		
		/**
		 * method adapted from 
		 * http://fragments.turtlemeat.com/javawebserver.php
		 */
		
		String s = "HTTP/1.0 ";
		// you probably have seen these if you have been surfing the web a while
		switch (return_code) {
		case 200:
			s = s + "200 OK";
			break;
		case 400:
			s = s + "400 Bad Request";
			break;
		case 403:
			s = s + "403 Forbidden";
			break;
		case 404:
			s = s + "404 Not Found";
			break;
		case 500:
			s = s + "500 Internal Server Error";
			break;
		case 501:
			s = s + "501 Not Implemented";
			break;
		}

		s = s + "\r\n"; // other header fields,
		s = s + "Connection: close\r\n"; // we can't handle persistent
											// connections
		s = s + "Server: WebServerVVS\r\n"; // server name

		// Construct the right Content-Type for the header.
		// This is so the browser knows what to do with the
		// file, you may know the browser dosen't look on the file
		// extension, it is the servers job to let the browser know
		// what kind of file is being transmitted. You may have experienced
		// if the server is miss configured it may result in
		// pictures displayed as text!
		switch (file_type) {
		// plenty of types for you to fill in
		case 0:
			break;
		case 1:
			s = s + "Content-Type: image/jpeg\r\n";
			break;
		case 2:
			s = s + "Content-Type: image/gif\r\n";
			break;
		case 3:
			s = s + "Content-Type: application/x-zip-compressed\r\n";
			break;
		case 4:
			s = s + "Content-Type: image/x-icon\r\n";
			break;
		case 5:
			s = s + "Content-type: text/css\r\n";
			break;
		case 6:
			s = s + "Content-type: text/plain\r\n";
			break;
		case 7:
			s = s + "Content-type: image/png\r\n";
			break;
		default:
			s = s + "Content-Type: text/plain\r\n";
			break;
		}

		s = s + "\r\n"; // this marks the end of the httpheader
		// and the start of the body
		// ok return our newly created header!
		return s;
	}
	
	
	private void listDirectory(File dir, String path) throws IOException {
		/**
		 * method used from 	http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServer.java
		 */
		@SuppressWarnings("unused")
		boolean status = dir.setReadOnly();
		PrintWriter ps = new PrintWriter(socket.getOutputStream(), true);
		ps.println("<HTML>");
		ps.println("<TITLE>Directory listing</TITLE><P>\n");
		ps.println("<BODY>");

		ps.println("<h4>" + "<A HREF=\"..\">Parent Directory</A>" + "</h4>");
		String[] list = dir.list();
		for (int i = 0; list != null && i < list.length; i++) {
			File f = new File(dir, list[i]);
			if (f.isDirectory()) {
				ps.println("<A HREF=\"" + path + "/" + list[i] + "/\">"
						+ list[i] + "/</A><BR>");
			} else {
				ps.println("<A HREF=\"" + path + "/" + list[i] + "\">"
						+ list[i] + "</A><BR>");
			}
		}
		ps.println("<P><HR><BR><I>" + (new Date()) + "</I><BR>");
		ps.println("</BODY>");
		ps.println("</HTML>");
	}

}// end ConnectionHandler
